﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;

using Vitruvian.Serialization;
using Vitruvian.Serialization.Xml;
using Vitruvian.Serialization.Formatters;
using Vitruvian.Windows.Serialization.Formatters;
using Vitruvian.Logging;
using Vitruvian.Testing;

namespace SpotItComponents
{
    /// <summary>
    /// Deck
    /// 
    /// To create a new deck, do the following:
    /// 
    ///     1. Construct a new deck object using one of the public constructors, e.g.
    ///         
    ///         Deck myDeck = new Deck("Nature Deck", false, MyBackImage);
    ///         
    ///     2. Setup the cards in the deck using one of two Deck Setup Director.  One diretor,
    ///     called DeckSetupDirectorUsingRandomSymbols, will select the necessary symbols randomly
    ///     from the set.  The other, called DeckSetupDirectorUsingSelectedSymbols, will only
    ///     use those that you have marked as selected.  See the Symbol.Selected property.  Here
    ///     are the steps for setting up the cards using a director.
    ///     
    ///          DeckSetupDirectorUsingRandomSymbols director = new DeckSetupDirectorUsingRandomSymbols
    ///          director.TargetDeck = this;
    ///          director.FromSymbolSet = ss;
    ///          director.NumberOfCards = numberOfCards;
    ///          director.Setup();
    ///
    ///     3. Add the deck to the server using Add method of the Deck Manager
    ///     
    /// </summary>
    public class Deck : Component
    {
        #region Private Data Members
        private static Logger logger = Logger.GetLogger(typeof(Deck));
        private string label;
        private bool isPrivate;
        private Guid owner;
        private List<Category> categories;
        private List<Card> cards;
        private Image backImage;

        #endregion

        #region Constructors and Creator Methods
        public Deck()
        {
            Initialize(null, false, null);
        }

        public Deck(string label, bool isPrivate)
        {
            Initialize(label, isPrivate, null);
        }

        public Deck(string label, bool isPrivate, Image backImage)
        {
            Initialize(label, isPrivate, backImage);
        }

        public Deck(string label, bool isPrivate, Deck origDeck)
        {
            Initialize(origDeck.label, isPrivate, origDeck.BackImage);

            foreach (Category category in Categories)
                this.Categories.Add(category);

            foreach (Card card in Cards)
                this.Cards.Add(card);
        }

        #endregion

        #region Public Properties and Methods

        public string Label
        {
            get { return label; }
            set { SetLabel(value) ; }
        }

        public bool IsPrivate
        {
            get { return isPrivate; }
            set { isPrivate = value; }
        }

        public Guid Owner
        {
            get { return owner; }
            set { owner = value; }
        }

        public List<Category> Categories
        {
            get { return categories; }
            set { categories = value; }
        }

        public List<Card> Cards
        {
            get { return cards; }
            set
            {
                cards = value;
            }
        }

        [ImageFormatter]
        public Image BackImage
        {
            get { return backImage; }
            set { backImage = value; }
        }

        public void Save(string fileName)
        {
            if (!string.IsNullOrEmpty(fileName))
                XmlFramework.Serialize(fileName, this);
            else
                throw new ApplicationException("The deck does not have a valid file name");
        }

        public void Load(string fileName)
        {
            if (!string.IsNullOrEmpty(fileName))
                XmlFramework.Deserialize(fileName, this);
            else
                throw new ApplicationException("The deck does not have a valid file name");
        }

        #endregion

        #region Private Methods
        private void Initialize(string label, bool isPrivate, Image backImage)
        {
            Id = Guid.NewGuid();
            SetLabel(label);
            IsPrivate = isPrivate;
            Categories = new List<Category>();
            Cards = new List<Card>();
            BackImage = backImage;
        }

        private void SetLabel(string newLabel)
        {
            label = (!string.IsNullOrEmpty(newLabel)) ? newLabel : "Unnamed Deck";
        }

        #endregion

        #region Unit Test Cases
#if (DEBUG)
        [Test(1)]
        private void Test_Deck_Construction_And_Properties()
        {
            Deck deck1 = new Deck();
            Assert.IsNotEqual(Guid.Empty, deck1.Id);
            Assert.Equals("Unnamed Deck", deck1.Label);
            Assert.IsFalse(deck1.IsPrivate);
            Assert.IsNotNull(deck1.Categories);
            Assert.Equals(0, deck1.Categories.Count);
            Assert.IsNull(deck1.BackImage);

            deck1 = new Deck("My Favorite Deck", true);
            Assert.IsNotEqual(Guid.Empty, deck1.Id);
            Assert.Equals("My Favorite Deck", deck1.Label);
            Assert.IsTrue(deck1.IsPrivate);
            Assert.IsNotNull(deck1.Categories);
            Assert.Equals(0, deck1.Categories.Count);
            Assert.IsNull(deck1.BackImage);

            Image backImage = new Bitmap("../../../Symbols/Background-1.jpg");
            deck1 = new Deck("Test Deck", true, backImage);
            Assert.IsNotEqual(Guid.Empty, deck1.Id);
            Assert.Equals("My Favorite Deck", deck1.Label);
            Assert.IsTrue(deck1.IsPrivate);
            Assert.IsNotNull(deck1.Categories);
            Assert.Equals(0, deck1.Categories.Count);
            Assert.IsNotNull(deck1.BackImage);

            Deck deck2 = new Deck("Copy of Test Deck", true, deck1);
            Assert.IsNotEqual(Guid.Empty, deck2.Id);
            Assert.Equals("My Favorite Deck", deck2.Label);
            Assert.IsTrue(deck2.IsPrivate);
            Assert.IsNotNull(deck2.Categories);
            Assert.Equals(0, deck2.Categories.Count);
            Assert.IsNotNull(deck2.BackImage);

            Guid testOwner = Guid.NewGuid();
            deck2.Owner = testOwner;
            Assert.Equals(testOwner, deck2.Owner);
        }

        

        [Test(3)]
        private void Test_Deck_Setup()
        {
            Deck deck1 = new Deck("Test Deck", true, backImage);
            Assert.IsNotEqual(Guid.Empty, deck1.Id);
            Assert.Equals("My Favorite Deck", deck1.Label);
            Assert.IsTrue(deck1.IsPrivate);
            Assert.IsNotNull(deck1.Categories);
            Assert.Equals(0, deck1.Categories.Count);
            Assert.IsNotNull(deck1.BackImage);

        }

        private void Test_SaveAndLoad()
        {
        }

#endif
        #endregion

    }
}
